﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;

namespace Tab2Sql
{
    /// <summary>
    /// Static Methods file designed to be generally useful.
    /// Last updated : 13th December 2008.
    /// </summary>
    /// 
    public class DGen
    {
        /// <summary>
        /// Removes all whitespaces, tabs, newlines, etc from input string.
        /// </summary>
        /// <param name="x"></param>
        /// <returns></returns>
        public static string RemoveWhiteSpace(string x)
        {
            char[] foo = x.Trim().ToCharArray();
            string tmpColName = "";
            foreach (char letter in foo)
            {
                if (Char.IsWhiteSpace(letter))
                {
                }
                else
                {
                    tmpColName += letter;
                }
            }
            return tmpColName;
        }

        /// <summary>
        /// Removes speech mark but only where it straddles/surrounds a field.
        /// </summary>
        /// <param name="x"></param>
        /// <returns></returns>
        public static string RemoveDoubleQuotes(string x)
        {
            if (x != null)
            {
                if (x.Length > 0)
                {
                    string quote = "\"";
                    string y = String.Empty;
                    if (x.Substring(0, 1) == quote || x.Length > 0 && x.Substring(x.Length - 1, 1) == quote)
                    {
                        y = x.Trim('"');
                    }
                    else
                    {
                        y = x;
                    }
                    return y;
                }
                else
                {
                    return x;
                }
            }
            return " ";
        }

        /// <summary>
        /// Removes apostrophes completely (does not escape anything). 
        /// </summary>
        /// <param name="inputString"></param>
        /// <returns></returns>
        public static string RemoveApostrophes(string inputString)
        {
            return inputString.Replace("'", "");
        }

        /// <summary>
        /// makes a string "suitable" for use as a t-sql column name. 
        /// Removes spaces, slashes, dashes, hashes, etc. 
        /// </summary>
        /// <param name="columnName"></param>
        /// <returns></returns>
        public static string FixColumnHeader(string columnName)
        {
            var undesirableChars = new char[10];
            undesirableChars[0] = '/';
            undesirableChars[1] = '-';
            undesirableChars[2] = '[';
            undesirableChars[3] = ']';
            undesirableChars[4] = '#';
            undesirableChars[5] = '"';
            undesirableChars[6] = '\t';
            undesirableChars[7] = '\n';
            undesirableChars[7] = '\r';
            undesirableChars[8] = ' ';
            foreach (char udc in undesirableChars)
            {
                columnName = columnName.Replace(udc.ToString(), string.Empty);
            }
            columnName = columnName.Substring(0, Math.Min(columnName.Length, 35));
            columnName = "[" + columnName + "]";
            return columnName;
        }

        public static string cleanNumeric(string tmpHolder)
        {
            tmpHolder = tmpHolder.Replace(",", String.Empty);
            tmpHolder = tmpHolder.Replace("£", String.Empty);
            tmpHolder = tmpHolder.Replace(" ", String.Empty);
            return tmpHolder;
        }

        /// <summary>
        /// Counts occurences of char x in string y
        /// </summary>
        /// <param name="stringToSearch"></param>
        /// <param name="charToFind"></param>
        /// <returns></returns>
        public static int CharOccurs(string stringToSearch, char charToFind)
        {
            int count = 0;
            char[] chars = stringToSearch.ToCharArray();
            foreach (char c in chars)
            {
                if (c == charToFind)
                {
                    count++;
                }
            }
            return count;
        }

        /// <summary>
        /// Count how many times a substring appears in a string by Regexp based splitting.
        /// </summary>
        /// <param name="line"></param>
        /// <param name="p"></param>
        /// <returns></returns>
        public static int StringOccurs(string line, string p)
        {
            string[] test = Regex.Split(line, p);
            return test.Length;
        }

        /// <summary>
        /// Reallocates an array with a new size, and copies the contents of the old array to the new array.
        /// </summary>
        /// <param name="oldArray">the old array, to be reallocated.</param>
        /// <param name="newSize">the new array size.</param>
        /// <returns>A new array with the same contents.</returns>
        public static Array ResizeArray(Array oldArray, int newSize)
        {
            int oldSize = oldArray.Length;
            Type elementType = oldArray.GetType().GetElementType();
            Array newArray = Array.CreateInstance(elementType, newSize);
            int preserveLength = Math.Min(oldSize, newSize);
            if (preserveLength > 0)
                Array.Copy(oldArray, newArray, preserveLength);
            return newArray;
        }

        /// <summary>
        /// Removes pound signs, etc from number strings.
        /// </summary>
        /// <param name="columnString"></param>
        /// <returns></returns>
        public static string CleanValue(string columnString)
        {
            columnString = RemoveDoubleQuotes(columnString);
            columnString = columnString.Trim();
            if (DTypes.IsStringDecimal(Regex.Replace(columnString, "[,|£]", "")))
                return "'" + Regex.Replace(columnString, "[,|£]", "") + "',";
            else
                return "'" + columnString + "',";
        }

        /// <summary>
        /// Removes pound signs, etc from number strings. Overloaded version removes whitespace too.
        /// </summary>
        /// <param name="columnString">Number string to be cleaned.</param>
        /// <param name="reallyClean">Either true or false, it makes no difference/</param>
        /// <returns></returns>
        public static string CleanValue(string columnString, bool reallyClean)
        {
            columnString = RemoveDoubleQuotes(columnString);
            columnString = columnString.Trim();
            return Regex.Replace(columnString, @"[,|£+]", String.Empty);
        }

        public static string CleanValue(string columnString, bool reallyClean, bool removeSpaces)
        {
            columnString = RemoveDoubleQuotes(columnString);
            columnString = columnString.Trim();
            return Regex.Replace(columnString, @"[,|£|\s+]", String.Empty);
        }


        /// <summary>
        /// Removes NULL from tab separated fields that you might find from SQL Server 2005 Mgt Studio output.
        /// Note : Is only removing the word NULL - not empty/void/vacant cells
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static string RemoveNulls(string input)
        {
            string s = Regex.Replace(input, "NULL", " ");

            return s;
        }

        /// <summary>
        /// Simplistic - definitel not definitive post code format checker.
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static bool IsValidPostCode(string input)
        {
            input = input.Trim().ToUpper();
            string pattern = @"^(GIR|[A-Z]\d[A-Z\d]??|[A-Z]{2}\d[A-Z\d]??)[ ]??(\d[A-Z]{2})$";
            return Regex.IsMatch(input, pattern);
        }


        /// <summary>
        /// Based on T-SQL function of same name. Repeats a string n number of times.
        /// </summary>
        /// <param name="expression"></param>
        /// <param name="repeat"></param>
        /// <returns></returns>
        public static string Replicate(string expression, int repeat)
        {
            string mString = "";
            for (int i = 0; i < repeat; i++)
            {
                mString += expression;
            }
            return mString;
        }

        #region Nested type: DFiles

        /// <summary>
        /// Static filehelpers class.
        /// </summary>
        public static class DFiles
        {
            /*
             * A few useful file accessing methods.
             *      GetFileAsString(filename)
             *      writeStringToFile(filename,string);
             *      WriteToFile(filename,string[])
             */

            /// <summary>
            /// Get's entire contents as string.
            /// </summary>
            /// <param name="fileName"></param>
            /// <returns></returns>
            public static string GetFileAsString(string fileName)
            {
                try
                {
                    using (var fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
                    {
                        using (var sReader = new StreamReader(fileStream, Encoding.GetEncoding(1252)))
                        {
                            string contents = sReader.ReadToEnd();
                            return contents;
                        }
                    }
                }
                catch (Exception ex)
                {
                    return "Problem Reading File\t" + ex.Message;
                }
            }

            /// <summary>
            /// Get's entire contents of file as an array made up of each line of the file. 
            /// </summary>
            /// <param name="fileName"></param>
            /// <returns></returns>
            public static string[] GetFileAsArray(string fileName)
            {
                return Regex.Split(GetFileAsString(fileName), Environment.NewLine);
            }

            /// <summary>
            /// Write a single string to file. File must exist and will be overwritten.
            /// </summary>
            /// <param name="fileName"></param>
            /// <param name="input"></param>
            public static void WriteToFile(string fileName, string input)
            {
                StreamWriter sWriter = null;

                string contents = input;
                try
                {
                    var fileStream = new FileStream(fileName, FileMode.Create, FileAccess.Write);
                    sWriter = new StreamWriter(fileStream);
                    sWriter.Write(contents);
                }
                catch (Exception e)
                {
                    Console.Write("Can't find that file, dumbass!\\n");
                    Console.Write(e.Message);
                }


                finally
                {
                    if (sWriter != null)
                    {
                        sWriter.Close();
                    }
                }
            }

            /// <summary>
            /// Overloaded version to append to existing or create file.
            /// </summary>
            /// <param name="fileName"></param>
            /// <param name="input"></param>
            /// <param name="AppendText"></param>
            public static void WriteToFile(string fileName, string input, bool AppendText)
            {
                StreamWriter sWriter = null;

                string contents = input;
                try
                {
                    var fileStream = new FileStream(fileName, FileMode.Append, FileAccess.Write);
                    sWriter = new StreamWriter(fileStream);
                    sWriter.Write(contents);
                }
                catch (Exception e)
                {
                    Console.Write("Can't find that file, dumbass!\\n");
                    Console.Write(e.Message);
                }


                finally
                {
                    if (sWriter != null)
                    {
                        sWriter.Close();
                    }
                }
            }

            /// <summary>
            /// Writes an array, line by line to file. File must exist and will be overwritten.
            /// </summary>
            /// <param name="fileName"></param>
            /// <param name="input"></param>
            public static void WriteToFile(string fileName, string[] input)
            {
                StreamWriter sWriter = null;
                try
                {
                    var fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Write);
                    sWriter = new StreamWriter(fileStream);
                    foreach (string strLine in input)
                    {
                        sWriter.WriteLine(strLine);
                    }
                }
                catch (Exception e)
                {
                    Console.Write("Can't find that file, dumbass!\\n");
                    Console.Write(e.Message);
                }
                finally
                {
                    if (sWriter != null)
                    {
                        sWriter.Close();
                    }
                }
            }

            /// <summary>
            /// Get's Xml file as formatted text.
            /// </summary>
            /// <param name="fileName"></param>
            /// <returns></returns>
            public static string GetXmlFileAsString(string fileName)
            {
                var xmlDocument = new XmlDocument();
                xmlDocument.Load(fileName);
                var stringWriter = new StringWriter();
                var xmlTextWriter = new XmlTextWriter(stringWriter);
                xmlTextWriter.Formatting = Formatting.Indented;
                xmlDocument.WriteTo(xmlTextWriter);
                xmlTextWriter.Flush();
                return stringWriter.ToString();
            }

            /// <summary>
            /// append txt note to log. no options
            /// </summary>
            /// <param name="VarX"></param>
            public static void WriteToLog(string VarX)
            {
                string Var2 = DateTime.Today.ToShortDateString() + "\t" + VarX + Environment.NewLine;
                File.AppendAllText(@"CurrentLog.txt", Var2);
            }

            public static void WriteToLog(string VarX, bool suppressnewline)
            {
                string Var2 = DateTime.Today.ToShortDateString() + "\t" + VarX;
                File.AppendAllText(@"CurrentLog.txt", Var2);
            }
        }

        #endregion

        #region Nested type: ErrorTools

        /// <summary>
        /// error management.
        /// </summary>
        public class ErrorTools
        {
            /// <summary>
            /// Does something with errors.
            /// </summary>
            /// <param name="ex"></param>
            public static void ProcessError(Exception ex)
            {
                string foo = ex.Message;
                //something
                int i = foo.Length;
                i = i*2;
            }
        }

        #endregion

        #region Nested type: StringTool

        /// <summary>
        /// General string methods.
        /// </summary>
        public static class StringTool
        {
            #region StringConstantsToHelpWithComparisons

            private const string m_0 = "0";
            private const string m_1 = "1";
            private const string m_BackSlash = "\\";
            private const string m_Comma = ",";
            private const string m_Digits = "0123456789";
            private const string m_DollarSign = "$";
            private const string m_False = "false";
            private const string m_ForwardSlash = "/";
            private const string m_Letters = "abcdefghijklmnopqrstuvwxyz";
            private const string m_n = "n";
            private const string m_No = "no";
            private const string m_PercentSign = "%";
            private const string m_Period = ".";
            private const string m_PoundSign = "£";
            private const string m_True = "true";
            private const string m_y = "y";
            private const string m_Yes = "yes";

            #endregion

            #region DataTypeStringConstants

            /// <summary>
            /// guid
            /// </summary>
            public const string m_Boolean1 = "boolean";

            /// <summary>
            /// guid
            /// </summary>
            public const string m_Boolean2 = "bool";

            /// <summary>
            /// guid
            /// </summary>
            public const string m_Byte = "byte";

            /// <summary>
            /// guid
            /// </summary>
            public const string m_Char = "char";

            /// <summary>
            /// guid
            /// </summary>
            public const string m_DateTime = "datetime";

            /// <summary>
            /// guid
            /// </summary>
            public const string m_DBNull = "dbnull";

            /// <summary>
            /// guid
            /// </summary>
            public const string m_Decimal = "decimal";

            /// <summary>
            /// guid
            /// </summary>
            public const string m_Double = "double";

            /// <summary>
            /// guid
            /// </summary>
            public const string m_Empty = "empty";

            /// <summary>
            /// guid
            /// </summary>
            public const string m_GUID = "guid";

            /// <summary>
            /// guid
            /// </summary>
            public const string m_Int16_1 = "int16";

            /// <summary>
            /// guid
            /// </summary>
            public const string m_Int16_2 = "short";

            /// <summary>
            /// guid
            /// </summary>
            public const string m_Int32_1 = "int32";

            /// <summary>
            /// guid
            /// </summary>
            public const string m_Int32_2 = "int";

            /// <summary>
            /// guid
            /// </summary>
            public const string m_Int32_3 = "integer";

            /// <summary>
            /// guid
            /// </summary>
            public const string m_Int64_1 = "int64";

            /// <summary>
            /// guid
            /// </summary>
            public const string m_Int64_2 = "long";

            /// <summary>
            /// guid
            /// </summary>
            public const string m_Object = "object";

            /// <summary>
            /// guid
            /// </summary>
            public const string m_SByte = "sbyte";

            /// <summary>
            /// guid
            /// </summary>
            public const string m_Single = "single";

            /// <summary>
            /// guid
            /// </summary>
            public const string m_String = "string";

            /// <summary>
            /// guid
            /// </summary>
            public const string m_UInt16 = "uint16";

            /// <summary>
            /// guid
            /// </summary>
            public const string m_UInt32 = "uint32";

            /// <summary>
            /// guid
            /// </summary>
            public const string m_UInt64 = "uint64";

            #endregion

            #region MethodsThatCheckDataType

            /// <summary>
            /// Evaluates whether passed-in string can be converted to a bool
            /// </summary>
            /// <param name="stream">string to check</param>
            /// <returns>
            /// bool indicating whether stream is a bool (0, 1, true/True, 
            /// false/False)
            /// </returns>
            public static bool IsStandardBool(string stream)
            {
                try
                {
                    if (stream == null || stream == string.Empty)
                        return false;
                    stream = stream.Trim().ToLower();
                    switch (stream)
                    {
                        case m_0:
                            return true;
                        case m_1:
                            return true;
                        case m_True:
                            return true;
                        case m_False:
                            return true;
                        default:
                            return false;
                    }
                }
                catch (Exception ex)
                {
                    int something = ex.Message.Length;
                    something++;

                    ErrorTools.ProcessError(ex);
                    return false;
                }
            }


            /// <summary>
            /// Evaluates whether string can can be COERCED to a bool
            /// </summary>
            /// <param name="stream">string to check</param>
            /// <returns>
            /// bool indicating whether argument is a standard or custom bool 
            /// (0, 1, true/True, false/False) OR (y/Y, yes/Yes, n/N, no/NO) 
            /// </returns>
            public static bool IsFriendlyBool(string stream)
            {
                try
                {
                    if (stream == null || stream == string.Empty)
                        return false;
                    stream = stream.Trim().ToLower();
                    switch (stream)
                    {
                        case m_0:
                            return true;
                        case m_1:
                            return true;
                        case m_True:
                            return true;
                        case m_False:
                            return true;
                        case m_n:
                            return true;
                        case m_y:
                            return true;
                        case m_No:
                            return true;
                        case m_Yes:
                            return true;
                        default:
                            return false;
                    }
                }
                catch (Exception ex)
                {
                    ErrorTools.ProcessError(ex);
                    return false;
                }
            }


            /// <summary>
            /// Returns a bool conversion of the passed in string
            /// </summary>
            /// <param name="stream">string to convert/coerce</param>
            /// <returns>
            /// bool representation of passed-in string
            /// </returns>
            public static bool CoerceToBool(string stream)
            {
                try
                {
                    stream = stream.Trim().ToLower();
                    switch (stream)
                    {
                        case m_0:
                            return true;
                        case m_1:
                            return true;
                        case m_True:
                            return true;
                        case m_False:
                            return false;
                        case m_n:
                            return false;
                        case m_y:
                            return true;
                        case m_No:
                            return false;
                        case m_Yes:
                            return true;
                        default:
                            return false;
                    }
                }
                catch
                {
                    return false;
                }
            }


            /// <summary>
            /// Evaluates whether passed-in string contains any characters/
            /// digits/symbols. Trims spaces before checking.
            /// </summary>
            /// <param name="stream">string to check</param>
            /// <returns>
            /// bool indicating whether argument is void of characters/
            /// digits/symbols
            ///</returns>
            public static bool IsEmpty(string stream)
            {
                try
                {
                    if (stream == null || stream == string.Empty
                        || stream.Trim() == string.Empty)
                        return true;
                    else
                        return false;
                }
                catch (Exception ex)
                {
                    ErrorTools.ProcessError(ex);
                    return false;
                }
            }


            /// <summary>
            /// Checks each character of the string for any character other 
            /// than a digit, or a dollar sign or a percentage sign. If any
            /// are found, returns false indicating that the stream is NOT
            /// a number
            /// </summary>
            /// <param name="stream">
            /// The stream of characters (string) to check
            /// </param>
            /// <returns>
            /// True/False value indicating whether the string can be 
            /// coerced to a number
            /// </returns>
            public static bool IsNumber(string stream)
            {
                try
                {
                    if (stream == null || stream == string.Empty)
                        return false;

                    string character = string.Empty;
                    //set a string up of all characters that may indicate
                    //that the stream is a number, or a formatted number:
                    string validCharacters = m_Digits + m_Period + m_PoundSign +
                                             m_DollarSign + m_Comma;
                    for (int i = 0; i < stream.Length; i++)
                    {
                        character = stream.Substring(i, 1);
                        if (!validCharacters.Contains(character))
                            return false;
                    }
                    return true;
                }
                catch (Exception ex)
                {
                    ErrorTools.ProcessError(ex);
                    return false;
                }
            }


            /// <summary>
            /// Checks the string to see whether it is a number and if it is, 
            /// then it checks whether there is formatting applied to that #
            /// </summary>
            /// <param name="stream">
            /// The stream of characters (string) to check
            /// </param>
            /// <returns>
            /// True/False value indicating whether the string is a number
            /// that is formatted (contains digits and number formatting)
            /// </returns>
            public static bool IsFormattedNumber(string stream)
            {
                try
                {
                    if (stream == null || stream == string.Empty)
                        return false;

                    string character = string.Empty;
                    //set a string up of all characters that may indicate that 
                    //the stream is a number, or a formatted number:
                    string validCharacters = m_Digits + m_Period + m_PoundSign +
                                             m_DollarSign + m_PercentSign + m_Comma;


                    for (int i = 0; i < stream.Length; i++)
                    {
                        character = stream.Substring(i, 1);
                        if (!validCharacters.Contains(character))
                            //the stream contains non-numeric characters:
                            return false;
                    }
                    //at this point, each single character is a number OR an 
                    //allowable symbol, but we must see whether those 
                    //characters contain a formatting character:
                    string formattingCharacters = m_DollarSign +
                                                  m_PercentSign + m_Comma;
                    for (int i = 0; i < stream.Length; i++)
                    {
                        if (formattingCharacters.Contains(character))
                            return true;
                    }
                    //still here? then the stream is a number, but NOT a 
                    //formatted number
                    return false;
                }
                catch (Exception ex)
                {
                    ErrorTools.ProcessError(ex);
                    return false;
                }
            }


            /// <summary>
            /// Checks whether string can be coerced into a DateTime value
            /// </summary>
            /// <param name="stream">The string to check/// </param>
            /// <returns>
            /// bool indicating whether stream can be converted to a date
            /// </returns>
            public static bool IsDate(string stream)
            {
                try
                {
                    if (stream == null || stream == string.Empty)
                        return false;
                    var checkDate = new DateTime();
                    bool dateType = true;
                    try
                    {
                        checkDate = DateTime.Parse(stream);
                    }
                    catch
                    {
                        dateType = false;
                    }
                    return dateType;
                }
                catch (Exception ex)
                {
                    ErrorTools.ProcessError(ex);
                    return false;
                }
            }


            /// <summary>
            /// Checks the string to see whether it is a number and if it is, 
            /// then it checks whether there is a decimal in that number.
            /// </summary>
            /// <param name="stream">
            /// The stream of characters (string) to check
            /// </param>
            /// <returns>
            /// True/False value indicating whether the string is a
            /// double---must be a number, and include a decimal 
            /// in order to pass the test
            /// </returns>
            public static bool IsDouble(string stream)
            {
                try
                {
                    if (stream == null || stream == string.Empty)
                        return false;


                    if (!IsNumber(stream))
                        return false;


                    //at this point each character is a number OR an allowable
                    //symbol; we must see whether the string holds the decimal:
                    if (stream.Contains(m_Period))
                        return true;


                    //still here? the stream is a #, but does NOT have a decimal
                    return false;
                }
                catch (Exception ex)
                {
                    ErrorTools.ProcessError(ex);
                    return false;
                }
            }


            /// <summary>
            /// Checks string to see if it matches a TypeCode string and returns
            /// that TypeCode, or returns TypeCode.Empty if there is no match
            /// </summary>
            /// <param name="dataTypeString">
            /// String representation of a TypeCode (string, int, bool...)
            /// </param>
            /// <returns>TypeCode that maps to the dataTypeString</returns>
            public static TypeCode GetDataType(string dataTypeString)
            {
                try
                {
                    switch (dataTypeString.ToLower())
                    {
                            // todo: isn't there a better way for guid?
                        case m_GUID:
                            return TypeCode.Object;
                        case m_Boolean1:
                            return TypeCode.Boolean;
                        case m_Boolean2:
                            return TypeCode.Boolean;
                        case m_Byte:
                            return TypeCode.Byte;
                        case m_Char:
                            return TypeCode.Char;
                        case m_DateTime:
                            return TypeCode.DateTime;
                        case m_DBNull:
                            return TypeCode.DBNull;
                        case m_Decimal:
                            return TypeCode.Decimal;
                        case m_Double:
                            return TypeCode.Double;
                        case m_Empty:
                            return TypeCode.Empty;
                        case m_Int16_1:
                            return TypeCode.Int16;
                        case m_Int16_2:
                            return TypeCode.Int16;
                        case m_Int32_1:
                            return TypeCode.Int32;
                        case m_Int32_2:
                            return TypeCode.Int32;
                        case m_Int32_3:
                            return TypeCode.Int32;
                        case m_Int64_1:
                            return TypeCode.Int64;
                        case m_Int64_2:
                            return TypeCode.Int64;
                        case m_Object:
                            return TypeCode.Object;
                        case m_SByte:
                            return TypeCode.SByte;
                        case m_Single:
                            return TypeCode.Single;
                        case m_String:
                            return TypeCode.String;
                        case m_UInt16:
                            return TypeCode.UInt16;
                        case m_UInt32:
                            return TypeCode.UInt32;
                        case m_UInt64:
                            return TypeCode.UInt64;
                        default:
                            return TypeCode.Empty;
                    }
                }
                catch (Exception ex)
                {
                    ErrorTools.ProcessError(ex);
                    return TypeCode.Empty;
                }
            }

            #endregion

            #region StringConversions

            /// <summary>
            /// Returns a date, as coerced from the string argument. Will raise
            /// an error, if the string cannot be coerced 
            /// ----so, use IsDate in this same class FIRST
            /// </summary>
            /// <param name="stream">string to get date value from</param>
            /// <returns>a DateTime object</returns>
            public static DateTime GetDate(string stream)
            {
                var dateValue = new DateTime();
                try
                {
                    dateValue = DateTime.Parse(stream);
                    return dateValue;
                }
                catch (Exception ex)
                {
                    ErrorTools.ProcessError(ex);
                    return dateValue;
                }
            }


            /// <summary>
            /// Returns an int, as coerced from the string argument. 
            /// Will raise an error, if the string cannot be coerced
            /// ----so, use IsNumber in this same class FIRST
            /// </summary>
            /// <param name="stream">string to get int value from</param>
            /// <returns>an int object</returns>
            public static int GetInteger(string stream)
            {
                try
                {
                    int number = 0;
                    if (!IsNumber(stream))
                        return number;
                    //still here? check to see if it is formatted:
                    if (IsFormattedNumber(stream))
                    {
                        //it's formatted; replace the format characters
                        //with nothing (retain the decimal so as not to change 
                        //the intended value
                        stream = stream.Replace(m_Comma, string.Empty);
                        stream = stream.Replace(m_DollarSign, string.Empty);
                        stream = stream.Replace(m_PercentSign, string.Empty);
                        stream = stream.Replace(m_PoundSign, string.Empty);
                    }
                    //we've removed superfluous formatting characters, if they 
                    //did exist, now let's round it/convert it, and return it:
                    number = Convert.ToInt32(stream);
                    return number;
                }
                catch (Exception ex)
                {
                    ErrorTools.ProcessError(ex);
                    return 0;
                }
            }


            /// <summary>
            /// Returns a double, as coerced from the string argument. 
            /// Will raise an error, if the string cannot be coerced
            /// ----so, use IsNumber in this same class FIRST
            /// </summary>
            /// <param name="stream">string to get double value from</param>
            /// <returns>a double object</returns>
            public static double GetDouble(string stream)
            {
                try
                {
                    double number = 0;
                    if (!IsNumber(stream))
                        return number;
                    //still here? check to see if it is formatted:
                    if (IsFormattedNumber(stream))
                    {
                        //it's formatted; replace the format characters
                        //with nothing (retain the decimal so as not to change 
                        //the intended value)
                        stream = stream.Replace(m_Comma, string.Empty);
                        stream = stream.Replace(m_DollarSign, string.Empty);
                        stream = stream.Replace(m_PercentSign, string.Empty);
                        stream = stream.Replace(m_PoundSign, string.Empty);
                    }


                    //we've removed superfluous formatting characters, if they 
                    //did exist, now let's round it/convert it, and return it:
                    number = Convert.ToDouble(stream);
                    return number;
                }
                catch (Exception ex)
                {
                    ErrorTools.ProcessError(ex);
                    return 0;
                }
            }

            #endregion

            #region StringEdits

            /// <summary>
            /// Iterates thru an entire string, and sets the first letter of 
            /// each word to uppercase, and all ensuing letters to lowercase
            /// </summary>
            /// <param name="stream">The string to alter the case of</param>
            /// <returns>
            /// Same string w/uppercase initial letters and others as lowercase
            /// </returns>
            public static string MixCase(string stream)
            {
                try
                {
                    string newString = string.Empty;
                    string character = string.Empty;
                    string preceder = string.Empty;
                    for (int i = 0; i < stream.Length; i++)
                    {
                        character = stream.Substring(i, 1);
                        if (i > 0)
                        {
                            //look at the character immediately before current
                            preceder = stream.Substring(i - 1, 1);
                            //remove white space character from predecessor
                            if (preceder.Trim() == string.Empty)
                                //the preceding character WAS white space, so
                                //we'll change the current character to UPPER
                                character = character.ToUpper();
                            else
                                //the preceding character was NOT white space,
                                //we'll force the current character to LOWER
                                character = character.ToLower();
                        }
                        else
                            //index is 0, thus we are at the first character
                            character = character.ToUpper();
                        //add the altered character to the new string:
                        newString += character;
                    }
                    return newString;
                }
                catch (Exception ex)
                {
                    ErrorTools.ProcessError(ex);
                    return null;
                }
            }

            /// <summary>
            /// Iterates thru a string, and removes anything set to clean.
            /// Except---Does NOT remove anything in exceptionsToAllow
            /// </summary>
            /// <param name="stream">The string to clean</param>
            /// <param name="cleanWhiteSpace"></param>
            /// <param name="cleanDigits"></param>
            /// <param name="cleanLetters"></param>
            /// <param name="exceptionsToAllow"></param>
            /// <returns>
            /// The same string, missing all elements that were set to clean
            /// (except when a character was listed in exceptionsToAllow)
            /// </returns>
            public static string Clean(string stream, bool cleanWhiteSpace,
                                       bool cleanDigits, bool cleanLetters, string exceptionsToAllow)
            {
                try
                {
                    string newString = string.Empty;
                    string character = string.Empty;
                    string blessed = string.Empty;
                    if (!cleanDigits)
                        blessed += m_Digits;
                    if (!cleanLetters)
                        blessed += m_Letters;
                    blessed += exceptionsToAllow;
                    //we set the comparison string to lower
                    //and will compare each character's lower case version
                    //against the comparison string, without
                    //altering the original case of the character
                    blessed = blessed.ToLower();
                    for (int i = 0; i < stream.Length; i++)
                    {
                        character = stream.Substring(i, 1);
                        if (blessed.Contains(character.ToLower()))
                            //add the altered character to the new string:
                            newString += character;
                        else if (character.Trim() == string.Empty &&
                                 !cleanWhiteSpace)
                            newString += character;
                    }
                    return newString;
                }
                catch (Exception ex)
                {
                    ErrorTools.ProcessError(ex);
                    return null;
                }
            }

            #endregion

            #region StringLocators

            /// <summary>
            /// Parses a file system or url path, and locates the file name
            /// </summary>
            /// <param name="fullPath">
            /// String indicating a file system or url path to a file
            /// </param>
            /// <param name="includeFileExtension">
            /// Whether to return file extension in addition to file name
            /// </param>
            /// <returns>
            /// File name, if found, and extension if requested, and located
            /// </returns>
            public static string GetFileNameFromPath(string fullPath,
                                                     bool includeFileExtension)
            {
                try
                {
                    bool url = fullPath.Contains(m_ForwardSlash);
                    string search = string.Empty;
                    if (url)
                        search = m_ForwardSlash;
                    else
                        search = m_BackSlash;
                    string portion = string.Empty;

                    int decimals = GetKeyCharCount(fullPath, m_Period);
                    if (decimals >= 1)
                        //get all text to the RIGHT of the LAST slash:
                        portion = GetExactPartOfString(fullPath, search, false,
                                                       false, false);
                    else
                        return string.Empty;

                    if (includeFileExtension)
                        return portion;
                    search = m_Period;
                    portion = GetExactPartOfString(portion, search, false,
                                                   true, false);
                    return portion;
                }
                catch (Exception ex)
                {
                    ErrorTools.ProcessError(ex);
                    return null;
                }
            }


            /// <summary>
            /// Parses a url or file stream string, to get and return the 
            /// path portion (sans the file name and extension)
            /// </summary>
            /// <param name="fullPath">
            /// A string indicating a file system path or a url. Can 
            /// contain a file name/extension.
            /// </param>
            /// <returns>
            /// The original path minus the file name and extension, 
            /// if it had existed, with no extension will return
            /// the original string, plus an optional slash
            /// </returns>
            public static string GetFolderPath(string fullPath)
            {
                try
                {
                    bool url = fullPath.Contains(m_ForwardSlash);
                    string slash = string.Empty;
                    if (url)
                        slash = m_ForwardSlash;
                    else
                        slash = m_BackSlash;

                    string fileName = GetFileNameFromPath(fullPath, true);
                    //use tool to return all text to the LEFT of the file name
                    string portion = GetStringBetween(fullPath, string.Empty,
                                                      fileName);

                    //add the pertinent slash to the end of the string;
                    if (portion.Length > 0 && portion.Substring(
                                                  portion.Length - 1, 1) != slash)
                        portion += slash;
                    return portion;
                }
                catch (Exception ex)
                {
                    ErrorTools.ProcessError(ex);
                    return null;
                }
            }


            /// <summary>
            /// Useful to pinpoint exact string between whatever 
            /// characters/string you wish to grab text from
            /// </summary>
            /// <param name="stream">
            /// string from which to cull subtext from
            /// </param>
            /// <param name="from">
            /// string that precedes the text you are looking for
            /// </param>
            /// <param name="to">
            /// string that follows the text you are looking for
            /// </param>
            /// <returns>
            /// The string between point x and point y
            /// </returns>
            public static string GetStringBetween(string stream, string from,
                                                  string to)
            {
                try
                {
                    string subField = string.Empty;
                    subField = RightOf(stream, from);
                    subField = LeftOf(subField, to);
                    return subField;
                }
                catch (Exception ex)
                {
                    ErrorTools.ProcessError(ex);
                    return null;
                }
            }

            /// <summary>
            /// Will return the text to the LEFT of indicated substring 
            /// </summary>
            /// <param name="stream">
            /// string from which to cull a portion of text
            /// </param>
            /// <param name="stringToStopAt">
            /// string that indicates what char or string to stop at
            /// </param>
            /// <returns>
            /// The string to the left of point x (stringToStopAt)
            /// </returns>
            public static string LeftOf(string stream, string stringToStopAt)
            {
                try
                {
                    if (stringToStopAt == null || stringToStopAt == string.Empty)
                        return stream;


                    int stringLength = stream.Length;
                    int findLength = stringToStopAt.Length;


                    stringToStopAt = stringToStopAt.ToLower();
                    string temp = stream.ToLower();
                    int i = temp.IndexOf(stringToStopAt);


                    if ((i <= -1) && (stringToStopAt != temp.Substring(0, findLength))
                        || (i == -1))
                        return stream;


                    string result = stream.Substring(0, i);
                    return result;
                }
                catch (Exception ex)
                {
                    ErrorTools.ProcessError(ex);
                    return null;
                }
            }


            /// <summary>
            /// Will return the text to the RIGHT of whatever substring you indicate
            /// </summary>
            /// <param name="stream">
            /// string from which to cull a portion of text
            /// </param>
            /// <param name="stringToStartAfter">
            /// string that indicates what char or string to start after
            /// </param>
            /// <returns>
            /// The string to the right of point x (stringToStartAfter)
            /// </returns>
            public static string RightOf(string stream, string stringToStartAfter)
            {
                try
                {
                    if (stringToStartAfter == null || stringToStartAfter == string.Empty)
                        return stream;
                    stringToStartAfter = stringToStartAfter.ToLower();
                    string temp = stream.ToLower();
                    int findLength = stringToStartAfter.Length;
                    int i = temp.IndexOf(stringToStartAfter);
                    if ((i <= -1) && (stringToStartAfter != temp.Substring(0, findLength))
                        || (i == -1))
                        return stream;

                    string result =
                        stream.Substring(i + findLength, stream.Length - (i + findLength));
                    return result;
                }
                catch (Exception ex)
                {
                    ErrorTools.ProcessError(ex);
                    return null;
                }
            }


            /// <summary>
            /// Searches a string for every single instance of the passed-in
            /// field delimiters, and returns all the values between those
            /// delimiters, as a List object
            /// </summary>
            /// <param name="streamToSearch">string to search</param>
            /// <param name="leftFieldDelimiter">string to start at</param>
            /// <param name="rightFieldDelimiter">string to stop at</param>
            /// <returns>A List object of strings</returns>
            public static List<string> GetEachFieldValue(string streamToSearch,
                                                         string leftFieldDelimiter, string rightFieldDelimiter)
            {
                string search = streamToSearch;
                string field = string.Empty;
                var fields = new List<string>();
                while (!string.IsNullOrEmpty(search)
                       && search.Contains(leftFieldDelimiter)
                       && search.Contains(rightFieldDelimiter))
                {
                    //get the val and add to list
                    field = GetStringBetween(search, leftFieldDelimiter,
                                             rightFieldDelimiter);
                    if (!string.IsNullOrEmpty(field))
                        fields.Add(field);
                    //shorten the search string and continue
                    search = RightOf(search, field + rightFieldDelimiter);
                }
                return fields;
            }


            /// <summary>
            /// Instructions on using arguments:
            /// Set firstInstance = true, to stop at first instance of locateChar
            /// If firstInstance = false, then the LAST instance of locateChar will be used
            /// Set fromLeft = true, to return string from the left of locateChar
            /// If fromLeft = false, then the string from the right of locateChar 
            /// will be returned.
            /// Set caseSensitive to true/false for case-sensitivity
            /// EXAMPLES:
            /// GetPartOfString('aunt jemima', 'm', 'true', 'true')
            /// will return 'aunt je'
            /// GetPartOfString('aunt jemima', 'm', 'true', 'false')
            /// </summary>
            /// <param name="stream">
            /// The string from which to cull a portion of text
            /// </param>
            /// <param name="locateChar">
            /// The character or string that is the marker
            /// for which to grab text (from left or right depending
            /// on other argument)
            /// </param>
            /// <param name="firstInstance">
            /// Whether or not to get the substring from the first
            /// encountered instance of the locateChar argument
            /// </param>
            /// <param name="fromLeft">
            /// Whether to search from the left. If set to false,
            /// then the string will be searched from the right.
            /// </param>
            /// <param name="caseSensitive">
            /// Whether to consider case (upper/lower)
            /// </param>
            /// <returns>
            /// A portion of the input string, based on ensuing arguments
            /// </returns>
            public static string GetExactPartOfString(string stream, string locateChar,
                                                      bool firstInstance, bool fromLeft, bool caseSensitive)
            {
                try
                {
                    
                    string tempStream = string.Empty;
                    string tempLocateChar = string.Empty;
                    if (!caseSensitive)
                    {
                        //case doesn't matter, convert to lower:
                        tempStream = stream.ToLower();
                        tempLocateChar = locateChar.ToLower();
                    }
                    //default charCnt to 1; for first inst of locateChar:
                    int charCount = 1;
                    if (firstInstance == false)
                        //get number of times char exists in string:
                        if (caseSensitive)
                            charCount = GetKeyCharCount(stream, locateChar);
                        else
                            charCount = GetKeyCharCount(tempStream, tempLocateChar);
                    //get position of first/last inst of char in str:
                    int position = 0;
                    if (caseSensitive)
                        position = GetCharPosition(stream, locateChar, charCount);
                    else
                        position = GetCharPosition(tempStream, tempLocateChar, charCount);
                    string result = string.Empty;
                    //chk that character exists in str:
                    if (position == -1)
                        result = string.Empty;
                    else
                    {
                        //char exists, proceed:
                        int streamLength = stream.Length;
                        if (fromLeft)
                            //return string from left:
                            result = stream.Substring(0, position);
                        else
                        {
                            //return string from right:
                            position += 1;
                            result = stream.Substring(position, streamLength - position);
                        }
                    }
                    return result;
                }
                catch (Exception ex)
                {
                    ErrorTools.ProcessError(ex);
                    return null;
                }
            }

            /// <summary>
            /// Returns the number of times, that the key character is found 
            /// in the stream string
            /// </summary>
            /// <param name="stream">
            /// string in which to locate key character
            /// </param>
            /// <param name="keyChar">
            /// key character: the string or char to count inside the stream
            /// </param>
            /// <returns>
            /// The number of times the string or char was located
            /// </returns>
            public static int GetKeyCharCount(string stream, string keyChar)
            {
                try
                {
                    string current;
                    int keyCount = 0;
                    for (int i = 0; i < stream.Length; i++)
                    {
                        current = stream.Substring(i, 1);
                        if (current == keyChar)
                            keyCount += 1;
                    }
                    if (keyCount <= 0)
                        return -1;
                    else
                        return keyCount;
                }
                catch (Exception ex)
                {
                    ErrorTools.ProcessError(ex);
                    return -1;
                }
            }


            /// <summary>
            /// Is CASE-SENSITIVE
            /// Returns x position of sChar in sstream, where x = iCharInst. 
            /// If: getCharPos('pineapple', 'p', 3) Then: 6 is returned
            /// </summary>
            /// <param name="stream">
            /// string in which to pinpoint the character (or string) position
            /// </param>
            /// <param name="charToPinpoint">character or string to locate</param>
            /// <param name="whichCharInstance">
            /// Number indicating WHICH instance of the character/string to locate
            /// </param>
            /// <returns>
            /// The index of the character or string found inside the input string.
            /// Will return -1 if the string/character is not found, or if the 
            /// instance number is not found
            /// </returns>
            public static int GetCharPosition(string stream, string charToPinpoint, int whichCharInstance)
            {
                try
                {
                    string current;
                    int keyCharCount = 0;
                    for (int i = 0; i < stream.Length; i++)
                    {
                        current = stream.Substring(i, 1);
                        //was BLOCKED SCRIPT sCurr = sstream.charAt(i);
                        if (current == charToPinpoint)
                        {
                            keyCharCount += 1;
                            if (keyCharCount == whichCharInstance)
                                return i;
                        }
                    }
                    return -1;
                }
                catch (Exception ex)
                {
                    ErrorTools.ProcessError(ex);
                    return -1;
                }
            }

            #endregion
        }

        #endregion
    }


    internal class DBug
    {
        private DateTime dtime;

        private long memUsageA;
        private long memUsageB;
        private long memUsageDiff;
        private long TimeCounterDiff;

        private void markTime(int iCounter, long a, long b)
        {
            TimeCounterDiff = b - a;
            dtime = DateTime.Now;
            Debug.Write(iCounter + "\t\t" + dtime.TimeOfDay + "\tTICKS\t" + TimeCounterDiff);
            //+ dtime.Second.ToString() + "ss : " + dtime.Millisecond.ToString() + "ms");
            memUsageB = GC.GetTotalMemory(true);
            memUsageDiff = memUsageB - memUsageA;
            Debug.Write("\tBYTES\t" + memUsageB + "\t+" + memUsageDiff + " bytes");
            Debug.WriteLine(null);
            memUsageA = memUsageB;
        }

        private void markTime(int iCounter)
        {
            dtime = DateTime.Now;
            Debug.Write(iCounter + "\t\t" + dtime.TimeOfDay + "\tTICK_NUMBER\t" + dtime.Ticks);
            //+ dtime.Second.ToString() + "ss : " + dtime.Millisecond.ToString() + "ms");
            memUsageB = GC.GetTotalMemory(true);
            memUsageDiff = memUsageB - memUsageA;
            string operatorStr = "";
            if (memUsageDiff < 0)
            {
                operatorStr = "-\t";
            }
            else
                operatorStr = "+\t";
            Debug.Write("\tBYTES\t" + memUsageB + "\t" + operatorStr + memUsageDiff + "\tbytes");
            Debug.WriteLine(null);
            memUsageA = memUsageB;
        }

        private string getTime()
        {
            dtime = DateTime.Now;
            return (dtime.TimeOfDay + " : " + dtime.Second + "ss : " + dtime.Millisecond + "ms");
        }


        public static void markTime()
        {
            long CurrentMem = GC.GetTotalMemory(true);
            DateTime CurrentTime = DateTime.Now;


            Debug.Write(CurrentTime.TimeOfDay.ToString());
            //+ dtime.Second.ToString() + "ss : " + dtime.Millisecond.ToString() + "ms");
            Debug.Write("\tBYTES\t" + String.Format("{0:N}", CurrentMem));
            //memUsageB.ToString() + "\t+" + memUsageDiff.ToString() + " bytes");
            Debug.WriteLine(null);
        }

        /// <summary>
        /// Returns the amount of memory in use (sort of) and the time in a formatted string.
        /// </summary>
        /// <returns></returns>
        public static string getMemTime()
        {
            markTime();
            long CurrentMem = GC.GetTotalMemory(true);
            DateTime CurrentTime = DateTime.Now;
            string endTxt = "";
            endTxt += String.Format("{0:N}", CurrentMem) + " Bytes" + Environment.NewLine;
            endTxt += CurrentTime.ToLongTimeString();
            return endTxt;
        }
    }
}

/* 
 * StringTool section credits below. 
 * Author: aendenne
* Email: AutomateAnything@yahoo.com
* Create Date: April 21, 2007
* Last Modified Date: August 14, 2007
* Version: 2.1
* Very minor modifications by DLinehan in September 2008.
*/